//
//  YHPopView.swift
//  FuweiCloud
//
//  Created by michael on 2024/10/16.
//

import UIKit
#if canImport(Haptica)
import Haptica
#endif
#if canImport(SnapKit)
import SnapKit
#endif

public typealias YHPopProperty = String

public extension YHPopProperty {
  static let viewTag = "YHPopViewTag"
  static let contentWidth = "YHPopContentWidth"
  static let contentHeight = "YHPopContentHeight"
  static let directionMargin = "YHPopDirectionMargin"
  static let touchOutside = "YHPopTouchOutside"
  static let cornerRadius = "YHPopCornerRadius"
  static let direction = "YHPopDirection"
  static let eventBlock = "YHPopEventBlock"
  static let topMargin = "YHPopTopMargin"
  static let bottomMargin = "YHPopBottomMargin"
  static let topPadding = "YHPopTopPadding"
  static let bottomPadding = "YHPopBottomPadding"
  static let headerWidth = "YHPopHeaderWidth"
  static let headerHeight = "YHPopHeaderHeight"
  static let headerPadding = "YHPopHeaderPadding"
  static let headerHorizon = "YHPopHeaderHorizon"
  static let headerAlign = "YHPopHeaderAlign"
  static let bodyWidth = "YHPopBodyWidth"
  static let bodyHeight = "YHPopBodyHeight"
  static let bodyPadding = "YHPopBodyPadding"
  static let bodyHorizon = "YHPopBodyHorizon"
  static let bodyAlign = "YHPopBodyAlign"
  static let footerWidth = "YHPopFooterWidth"
  static let footerHeight = "YHPopFooterHeight"
  static let footerPadding = "YHPopFooterPadding"
  static let footerHorizon = "YHPopFooterHorizon"
  static let fitHeight = "YHPopFitHeight"
  static let ignoreDismiss = "YHPopIgnoreDismiss"
  static let buttonSpacing = "YHPopButtonSpacing"
  static let leftButton = "YHPopLeftButton"
  static let leftButtonWidth = "YHPopLeftButtonWidth"
  static let rightButton = "YHPopRightButton"
  static let header = "YHPopHeader"
  static let maskBackground = "YHPopMaskBackground"
  static let body = "YHPopBody"
  static let darkMode = "FWDarkMode"
  static let footer = "YHPopFooter"
  static let timeout = "YHPopTimeout"
  static let timeoutBlock = "YHPopTimeoutBlock"
}

public enum YHPopViewDirection: Int {
  case center, bottom, top, left, right
}

@objcMembers
open class YHPopView: UIView {
  private static let BASE_TAG = 290747
  public static let HUD_TAG = 536920
  public static let maxPopWidth = min(YHScreenW, 430)
  /// pop view tag
  open var viewTag: Int { properties?[.viewTag] as? Int ?? Self.BASE_TAG }
  
  open lazy var contentWidth = properties?[.contentWidth] as? CGFloat ?? UIScreen.main.bounds.width
  
  open lazy var contentHeight = properties?[.contentHeight] as? CGFloat ?? 245

  /// 非中心弹窗时，贴边的间距
  open var directionMargin: CGFloat { properties?[.directionMargin] as? CGFloat ?? 0 }
  /// 是否点击空白区域时dismiss
  open var touchOutside: Bool { properties?[.touchOutside] as? Bool ?? (direction != .center) }
  /// 弹窗圆角
  open var cornerRadius: CGFloat { properties?[.cornerRadius] as? CGFloat ?? 8 }
  /// 弹窗弹出方向
  open var direction: YHPopViewDirection { properties?[.direction] as? YHPopViewDirection ?? .center }
    
  /// 是否可以被YHPopView.dismiss()
  open var ignoreDismiss: Bool { properties?[.ignoreDismiss] as? Bool ?? false }
    
  /// 是否是暗黑模式
  open var darkMode: Bool { properties?[.darkMode] as? Bool ?? onDarkMode }
    
  /// 遮罩的背景色
  open var maskBackground: UIColor { properties?[.maskBackground] as? UIColor ?? .black.alpha(0.5) }
    
  public var eventBlock: ((Any?) -> Void)?
    
  public private(set) var contentView: UIView!
  public var userInfo: Any?
    
  public var properties: [YHPopProperty: Any]? { userInfo as? [YHPopProperty: Any] }
    
  private var backgroundView: UIView!
    
  public required init(userInfo: Any?, eventBlock: ((Any?) -> Void)? = nil) {
    super.init(frame: UIScreen.main.bounds)
    self.userInfo = userInfo
    self.eventBlock = eventBlock
    setupView()
  }
    
  public required init(properties: [YHPopProperty: Any]?, eventBlock: ((Any?) -> Void)? = nil) {
    super.init(frame: UIScreen.main.bounds)
    self.userInfo = properties
    self.eventBlock = eventBlock
    setupView()
  }

  required public init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
    
  private func setupView() {
    backgroundView = UIView(color: .black.alpha(0))
        
    backgroundView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(backgroundTapped)))
    contentView = UIView(color: darkMode ?.gray("2C"): .white)
    initContentUI()
    if cornerRadius > 0 {
//            contentView.clipsToBounds = true
      contentView.addCorner(cornerRadius)
    }
        
    if direction == .center {
      contentView.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
      contentView.alpha = 0
    }
    addSubviews([backgroundView, contentView])
#if canImport(SnapKit)
    backgroundView.snp.makeConstraints { make in
      make.edges.equalToSuperview()
    }
    contentView.snp.makeConstraints { make in
      make.width.equalTo(contentWidth)
      make.height.equalTo(contentHeight)
      switch direction {
      case .center:
        make.centerX.equalToSuperview()
        make.centerY.equalToSuperview()
      case .bottom:
        make.centerX.equalToSuperview()
        make.bottom.equalTo(contentHeight+directionMargin)
      case .top:
        make.centerX.equalToSuperview()
        make.top.equalTo(-contentHeight-directionMargin)
      case .left:
        make.centerY.equalToSuperview()
        make.left.equalTo(-contentWidth-directionMargin)
      case .right:
        make.centerY.equalToSuperview()
        make.right.equalTo(contentWidth+directionMargin)
      }
    }
#endif
  }
    
  @objc private func backgroundTapped() {
    if touchOutside {
      dismiss()
    }
  }
    
  open func initContentUI() {
    // Override in subclass if needed
  }
    
  public func show() {
#if canImport(Haptica)
    Haptic.impact(.medium).generate()
#endif
    if direction == .center {
      UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 15, options: .curveLinear) {
        self.backgroundView.backgroundColor = self.maskBackground
        self.contentView.transform = .identity
        self.contentView.alpha = 1
      }
    } else {
#if canImport(SnapKit)
      contentView.snp.updateConstraints { make in
        switch direction {
        case .bottom:
          make.bottom.equalTo(-directionMargin)
        case .top:
          make.top.equalTo(directionMargin)
        case .left:
          make.left.equalTo(directionMargin)
        default:
          make.right.equalTo(-directionMargin)
        }
      }
#endif
      UIView.animate(withDuration: 0.3) {
        self.layoutIfNeeded()
        self.backgroundView.backgroundColor = self.maskBackground
      }
    }
  }
    
  public func dismiss(_ userInfo: Any? = nil, triggerEvent: Bool = true, animated: Bool = true) {
    if triggerEvent {
      eventBlock?(userInfo)
    }
    eventBlock = nil
    if animated {
      if direction != .center {
#if canImport(SnapKit)
        contentView.snp.updateConstraints { make in
          switch direction {
          case .bottom:
            make.bottom.equalTo(contentHeight+directionMargin)
          case .top:
            make.top.equalTo(-contentHeight-directionMargin)
          case .left:
            make.left.equalTo(-contentWidth-directionMargin)
          default:
            make.right.equalTo(contentWidth+directionMargin)
          }
        }
#endif
      }
      UIView.animate(withDuration: 0.3, animations: {
        self.backgroundView.backgroundColor = .black.alpha(0)
        if self.direction != .center {
          self.layoutIfNeeded()
        } else {
          self.contentView.alpha = 0
        }
      }) { _ in
        self.removeFromSuperview()
      }
    } else {
      removeFromSuperview()
    }
  }
    
  @discardableResult
  public class func pop(userInfo: Any, on view: UIView? = nil, eventBlock: ((Any?) -> Void)? = nil) -> Self {
    let popView = Self(userInfo: userInfo, eventBlock: eventBlock)
    popView.pop(on: view)
    return popView
  }
    
  @discardableResult
  public class func pop(properties: [YHPopProperty: Any], on view: UIView? = nil, eventBlock: ((Any?) -> Void)? = nil) -> Self {
    let popView = Self(properties: properties, eventBlock: eventBlock)
    popView.pop(on: view)
    return popView
  }
    
  @discardableResult
  public class func pop(on view: UIView? = nil, eventBlock: ((Any?) -> Void)? = nil) -> Self {
    dismiss(on: view, animated: false)
    let popView = Self(userInfo: nil, eventBlock: eventBlock)
    popView.pop(on: view)
    return popView
  }

  public func pop(on view: UIView? = nil) {
    let superView = view ?? YHKeyWindowView
    tag = viewTag
    Self.dismiss(on: superView, viewTag: viewTag, animated: false)
    superView?.addSubview(self)
    DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
      self.show()
    }
  }

  #warning("需要隐藏HUD加载弹窗时，请不要直接使用这个方法，请使用`HideHUD(_:animatd:)`")
  public class func dismiss(on view: UIView? = nil, viewTag: Int = 0, animated: Bool, forcely: Bool = false, hideHUDTag: Bool = true) {
    let vtag = viewTag == 0 ? BASE_TAG : viewTag // HUD_TAG
    popViewDismiss(YHKeyWindowView?.viewWithTag(vtag), animated: animated, forcely: forcely)
    if let view = view, view != YHKeyWindowView {
      popViewDismiss(view.viewWithTag(vtag), animated: animated, forcely: forcely)
    }
    if hideHUDTag {
      popViewDismiss(YHKeyWindowView?.viewWithTag(HUD_TAG), animated: animated, forcely: forcely)
      if let view = view, view != YHKeyWindowView {
        popViewDismiss(view.viewWithTag(HUD_TAG), animated: animated, forcely: forcely)
      }
    }
  }
    
  private class func popViewDismiss(_ popView: UIView?, animated: Bool, forcely: Bool) {
    if let popView {
      if let popView = popView as? YHPopView, forcely || !popView.ignoreDismiss {
        popView.dismiss(triggerEvent: false, animated: animated)
      }
    }
  }
    
  public class func isVisible(on view: UIView? = nil, viewTag: Int = 0) -> Bool {
    let vtag = viewTag == 0 ? BASE_TAG : viewTag
    return (view ?? YHKeyWindowView)?.viewWithTag(vtag) != nil
  }
    
  deinit {
    print("[\(NSStringFromClass(Self.self)) deinit]")
  }
}

public extension YHPopView {
  @MainActor
  @discardableResult
  class func pop(userInfo: Any, on view: UIView? = nil) async -> Any? {
    await withUnsafeContinuation { c in
      _ = pop(userInfo: userInfo, on: view) { c.resume(returning: $0) }
    }
  }

  @MainActor
  @discardableResult
  class func pop(properties: [YHPopProperty: Any], on view: UIView? = nil) async -> Any? {
    await withUnsafeContinuation { c in
      _ = pop(properties: properties, on: view) { c.resume(returning: $0) }
    }
  }

  @MainActor
  @discardableResult
  class func pop(on view: UIView? = nil) async -> Any? {
    await withUnsafeContinuation { c in
      _ = pop(on: view) { c.resume(returning: $0) }
    }
  }
}
